package jpm.position;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import jpm.position.Cache.UpdateStatus;
import jpm.trade.Trade;
import jpm.trade.TradeHelper.Operation;

import org.junit.Before;
import org.junit.Test;

public class CacheTest {

	@Before
	public void setUp() {
		Cache.clearCache();
	}

	@Test
	public void canProcessNewBuyTrade() {
		Trade tradeProp = new Trade(1, 1, "GOOG", 100, true, "ACC-123",
				Operation.NEW);

		UpdateStatus status = Cache.update(tradeProp);
		assertEquals(UpdateStatus.SUCCESS, status);

		// check if position cache is properly updated
		Map<PositionKey, PositionValue> positionCache = Cache
				.getPositionCache();
		assertEquals(1, positionCache.size());

		PositionKey positionKeyProp = positionCache.keySet().iterator().next();
		assertEquals("ACC-123", positionKeyProp.getAccountNo());
		assertEquals("GOOG", positionKeyProp.getSecurity());

		PositionValue positionValueProp = positionCache.get(positionKeyProp);
		assertEquals(100, positionValueProp.getQuantity());
		assertEquals(1, positionValueProp.getTradeIds().size());
		assertTrue(positionValueProp.getTradeIds().contains(1));

		// trade cache should be properly updated
		Map<Integer, Trade> trades = Cache.getTradeCache();
		assertEquals(1, trades.size());
		tradeProp = trades.get(1);
		assertEquals(1, tradeProp.getTradeId());
		assertEquals(1, tradeProp.getTradeVersion());
		assertEquals("GOOG", tradeProp.getSecurity());
		assertEquals(100, tradeProp.getQuantity());
		assertEquals(true, tradeProp.isBuy());
		assertEquals("ACC-123", tradeProp.getAccountNo());

		// should be nothing in pending delete
		Map<Integer, Trade> pendingCancels = Cache.getPendingCancels();
		assertEquals(0, pendingCancels.size());
	}

	@Test
	public void canProcessDuplicateNewTrade() {
		Trade tradeProp = new Trade(1, 1, "MSFT", 100, true, "ACC-123",
				Operation.NEW);

		UpdateStatus status = Cache.update(tradeProp);
		assertEquals(UpdateStatus.SUCCESS, status);

		// check if position cache is properly updated
		Map<PositionKey, PositionValue> positionCache = Cache
				.getPositionCache();

		PositionValue positionValueProp = positionCache.get(new PositionKey(
				tradeProp.getSecurity(), tradeProp.getAccountNo()));

		assertEquals(100, positionValueProp.getQuantity());

		// fire the same event again
		status = Cache.update(tradeProp);

		assertEquals(1, positionCache.size());

		assertEquals(100, positionValueProp.getQuantity());

		// fire the same event a few more times
		status = Cache.update(tradeProp);
		status = Cache.update(tradeProp);
		status = Cache.update(tradeProp);
		status = Cache.update(tradeProp);

		assertEquals(1, positionCache.size());
		assertEquals(100, positionValueProp.getQuantity());
	}

	@Test
	public void canProcessNewBuyAmendCancelSequence() {
		Trade tradeProp = new Trade(1, 1, "MSFT", 100, true, "ACC-123",
				Operation.NEW);

		UpdateStatus status = Cache.update(tradeProp);
		assertEquals(UpdateStatus.SUCCESS, status);
		Map<PositionKey, PositionValue> positionCache = Cache
				.getPositionCache();
		PositionValue positionValueProp = positionCache.get(new PositionKey(
				tradeProp.getSecurity(), tradeProp.getAccountNo()));
		assertEquals(100, positionValueProp.getQuantity());

		// amend quantity to 170
		tradeProp = new Trade(1, 2, "MSFT", 170, true, "ACC-123",
				Operation.AMEND);
		Cache.update(tradeProp);
		assertEquals(170, positionValueProp.getQuantity());
		Map<Integer, Trade> tradeCache = Cache.getTradeCache();
		assertEquals(170, tradeCache.get(1).getQuantity());

		// amend quantity to 225 (same trade version. trade should get over
		// written)
		tradeProp = new Trade(1, 2, "MSFT", 225, true, "ACC-123",
				Operation.AMEND);
		Cache.update(tradeProp);
		assertEquals(225, positionValueProp.getQuantity());
		tradeCache = Cache.getTradeCache();
		assertEquals(225, tradeCache.get(1).getQuantity());

		// amend quantity to 300 but previous version. trade should be ignored
		tradeProp = new Trade(1, 1, "MSFT", 300, true, "ACC-123",
				Operation.AMEND);
		status = Cache.update(tradeProp);
		assertEquals(UpdateStatus.IGNORED, status);
		assertEquals(225, positionValueProp.getQuantity());
		assertEquals(225, tradeCache.get(1).getQuantity());

		// cancel trade
		tradeProp = new Trade(1, 3, "MSFT", 0, true, "ACC-123",
				Operation.CANCEL);
		Cache.update(tradeProp);
		assertEquals(0, positionValueProp.getQuantity());
		assertEquals(0, tradeCache.get(1).getQuantity());
	}

	@Test
	public void canProcessNewSellAmendCancelSequence() {
		Trade tradeProp = new Trade(1, 1, "MSFT", 100, false, "ACC-123",
				Operation.NEW);

		UpdateStatus status = Cache.update(tradeProp);
		assertEquals(UpdateStatus.SUCCESS, status);
		Map<PositionKey, PositionValue> positionCache = Cache
				.getPositionCache();
		PositionValue positionValueProp = positionCache.get(new PositionKey(
				tradeProp.getSecurity(), tradeProp.getAccountNo()));
		assertEquals(-100, positionValueProp.getQuantity());

		// amend quantity to 170
		tradeProp = new Trade(1, 2, "MSFT", 170, false, "ACC-123",
				Operation.AMEND);
		Cache.update(tradeProp);
		assertEquals(-170, positionValueProp.getQuantity());
		Map<Integer, Trade> tradeCache = Cache.getTradeCache();
		assertEquals(170, tradeCache.get(1).getQuantity());

		// amend quantity to 225 (same trade version. trade should get over
		// written)
		tradeProp = new Trade(1, 2, "MSFT", 225, false, "ACC-123",
				Operation.AMEND);
		Cache.update(tradeProp);
		assertEquals(-225, positionValueProp.getQuantity());
		tradeCache = Cache.getTradeCache();
		assertEquals(225, tradeCache.get(1).getQuantity());
		assertEquals(false, tradeCache.get(1).isBuy());

		// amend quantity to 300 but previous version. trade should be ignored
		tradeProp = new Trade(1, 1, "MSFT", 300, false, "ACC-123",
				Operation.AMEND);
		status = Cache.update(tradeProp);
		assertEquals(UpdateStatus.IGNORED, status);
		assertEquals(-225, positionValueProp.getQuantity());
		assertEquals(225, tradeCache.get(1).getQuantity());

		// cancel trade
		tradeProp = new Trade(1, 3, "MSFT", 0, false, "ACC-123",
				Operation.CANCEL);
		Cache.update(tradeProp);
		assertEquals(0, positionValueProp.getQuantity());
		assertEquals(0, tradeCache.get(1).getQuantity());
	}

	@Test
	public void deleteBeforeActualTradeIsAddedToPendingQueueAndProcessedWhenActualTradeArrives() {
		// version 1: trade was created with quantity 100 sell
		// version 2: trade was amended to 165
		// version 3: trade was cancelled

		// but events arrive in this order: 3, 2, 1

		// cancel event first
		Trade tradeProp = new Trade(1, 3, "MSFT", 0, false, "ACC-123",
				Operation.CANCEL);
		UpdateStatus status = Cache.update(tradeProp);
		assertEquals(UpdateStatus.PENDING_CANCEL, status);

		// position cache and trade cache should be empty
		Map<PositionKey, PositionValue> positionCache = Cache
				.getPositionCache();
		assertEquals(0, positionCache.size());
		Map<Integer, Trade> tradeCache = Cache.getTradeCache();
		assertEquals(0, tradeCache.size());

		// pending cancel map should have 1 entry
		Map<Integer, Trade> pendingCancels = Cache.getPendingCancels();
		assertEquals(1, pendingCancels.size());
		assertEquals(1, pendingCancels.get(1).getTradeId());
		assertEquals(3, pendingCancels.get(1).getTradeVersion());
		assertEquals("MSFT", pendingCancels.get(1).getSecurity());
		assertEquals(0, pendingCancels.get(1).getQuantity());
		assertEquals(false, pendingCancels.get(1).isBuy());
		assertEquals("ACC-123", pendingCancels.get(1).getAccountNo());
		assertEquals(Operation.CANCEL, pendingCancels.get(1).getOperation());

		// amend event
		tradeProp = new Trade(1, 2, "MSFT", 165, false, "ACC-123",
				Operation.AMEND);
		status = Cache.update(tradeProp);
		assertEquals(UpdateStatus.SUCCESS, status);

		// position cache should have an entry. quantity is zero and should have
		// the deleted trade
		assertEquals(1, positionCache.size());
		PositionValue positionValueProp = positionCache.get(new PositionKey(
				tradeProp.getSecurity(), tradeProp.getAccountNo()));
		assertEquals(0, positionValueProp.getQuantity());
		assertEquals(1, positionValueProp.getTradeIds().size());
		assertTrue(positionValueProp.getTradeIds().contains(1));

		// trade cache should have the latest version
		assertEquals(1, tradeCache.get(1).getTradeId());
		assertEquals(3, tradeCache.get(1).getTradeVersion());
		assertEquals(0, tradeCache.get(1).getQuantity());

		// pendingCancel queue is cleared
		assertEquals(0, pendingCancels.size());

		// new event
		tradeProp = new Trade(1, 1, "MSFT", 100, false, "ACC-123",
				Operation.AMEND);

		status = Cache.update(tradeProp);
		assertEquals(UpdateStatus.IGNORED, status);

		// no change in position cache and trade cache
		assertEquals(1, positionCache.size());
		assertEquals(0, positionValueProp.getQuantity());
		assertEquals(1, positionValueProp.getTradeIds().size());
		assertTrue(positionValueProp.getTradeIds().contains(1));

		assertEquals(1, tradeCache.get(1).getTradeId());
		assertEquals(3, tradeCache.get(1).getTradeVersion());
		assertEquals(0, tradeCache.get(1).getQuantity());
	}

	@Test
	public void realScenarioSimpleCase() throws InterruptedException,
			ExecutionException {

		// trades can come in order from multiple threads

		// trade 1: buy MSFT using account ACC-123
		// version 1: new 100
		// version 2: amend to 225
		// version 3: amend to 300
		// version 4: amend to 1010
		// version 5: amend to 445
		// version 6: amend to 860
		// version 7: amend to 800
		// version 8: amend to 950

		List<Trade> trades = new ArrayList<>();
		trades.add(new Trade(1, 1, "MSFT", 100, true, "ACC-123", Operation.NEW));
		trades.add(new Trade(1, 2, "MSFT", 225, true, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(1, 3, "MSFT", 300, true, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(1, 4, "MSFT", 345, true, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(1, 5, "MSFT", 445, true, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(1, 6, "MSFT", 600, true, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(1, 7, "MSFT", 800, true, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(1, 8, "MSFT", 950, true, "ACC-123",
				Operation.AMEND));

		Collections.shuffle(trades);
		assertEquals(8, trades.size());

		ExecutorService executorService = Executors.newFixedThreadPool(4);

		List<Future<?>> futures = new ArrayList<>(trades.size());
		for (final Trade tradeProp : trades) {
			Future<?> future = executorService.submit(new Runnable() {

				@Override
				public void run() {
					Cache.update(tradeProp);
				}
			});

			futures.add(future);
		}
		assertEquals(futures.size(), trades.size());

		// ensure no exception is thrown
		for (int i = 0; i < futures.size(); i++) {
			futures.get(i).get();
		}

		executorService.shutdown();
		executorService.awaitTermination(30, TimeUnit.SECONDS);

		Map<PositionKey, PositionValue> positionCache = Cache
				.getPositionCache();

		assertEquals(1, positionCache.size());
		PositionValue positionValueProp = positionCache.get(new PositionKey(
				"MSFT", "ACC-123"));
		assertEquals(950, positionValueProp.getQuantity());
		assertEquals(1, positionValueProp.getTradeIds().size());
		assertTrue(positionValueProp.getTradeIds().contains(1));

		Map<Integer, Trade> tradeCache = Cache.getTradeCache();
		assertEquals(950, tradeCache.get(1).getQuantity());
	}

	@Test
	public void realScenarioComplexCase() throws InterruptedException,
			ExecutionException {

		// trades can come in order from multiple threads

		// trade 1: buy MSFT using account ACC-123
		// version 1: new 100
		// version 2: amend to 225
		// version 3: amend to 300
		// version 4: amend to 1010
		// version 5: amend to 445
		// version 6: amend to 860
		// version 7: amend to 800
		// version 8: amend to 950

		final List<Trade> trades = new ArrayList<>();
		trades.add(new Trade(1, 1, "MSFT", 100, true, "ACC-123", Operation.NEW));
		trades.add(new Trade(1, 2, "MSFT", 225, true, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(1, 3, "MSFT", 300, true, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(1, 4, "MSFT", 345, true, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(1, 5, "MSFT", 445, true, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(1, 6, "MSFT", 600, true, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(1, 7, "MSFT", 800, true, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(1, 8, "MSFT", 950, true, "ACC-123",
				Operation.AMEND));

		// trade 2: sell MSFT using account ACC-123
		// version 1: new 50
		// version 2: amend to 350
		// version 3: amend to 450
		trades.add(new Trade(2, 1, "MSFT", 50, false, "ACC-123", Operation.NEW));
		trades.add(new Trade(2, 2, "MSFT", 350, false, "ACC-123",
				Operation.AMEND));
		trades.add(new Trade(2, 3, "MSFT", 450, false, "ACC-123",
				Operation.AMEND));

		// trade 3: sell MSFT using different account ACC-231
		// version 1: new 65
		// version 2: amend to 95
		trades.add(new Trade(3, 1, "MSFT", 65, false, "ACC-231", Operation.NEW));
		trades.add(new Trade(3, 2, "MSFT", 95, false, "ACC-231",
				Operation.AMEND));

		// trade 4: sell GOOG using ACC-231
		// version 1: new 85
		// version 2: amend 105
		// version 3: amend 100
		// version 4: cancel
		trades.add(new Trade(4, 1, "GOOG", 85, false, "ACC-231", Operation.NEW));
		trades.add(new Trade(4, 2, "GOOG", 105, false, "ACC-231",
				Operation.AMEND));
		trades.add(new Trade(4, 3, "GOOG", 100, false, "ACC-231",
				Operation.AMEND));
		trades.add(new Trade(4, 4, "GOOG", 0, false, "ACC-231",
				Operation.CANCEL));

		Collections.shuffle(trades);

		ExecutorService executorService = Executors.newFixedThreadPool(8);

		List<Future<?>> futures = new ArrayList<>(trades.size());
		for (int i = 0; i < trades.size(); i++) {
			final Trade trade = trades.get(i);
			Future<?> future = executorService.submit(new Runnable() {

				@Override
				public void run() {
					Cache.update(trade);
				}
			});
			futures.add(future);
		}

		// ensure no exception is thrown
		for (Future<?> future : futures) {
			future.get();
		}

		executorService.shutdown();
		executorService.awaitTermination(30, TimeUnit.SECONDS);

		Map<PositionKey, PositionValue> positionCache = Cache
				.getPositionCache();

		// position: ACC-123|MSFT
		PositionValue positionValueProp = positionCache.get(new PositionKey(
				"MSFT", "ACC-123"));
		assertEquals(500, positionValueProp.getQuantity());
		assertEquals(2, positionValueProp.getTradeIds().size());
		assertTrue(positionValueProp.getTradeIds().contains(1));
		assertTrue(positionValueProp.getTradeIds().contains(2));

		// ACC-231|MSFT
		positionValueProp = positionCache
				.get(new PositionKey("MSFT", "ACC-231"));
		assertEquals(-95, positionValueProp.getQuantity());
		assertEquals(1, positionValueProp.getTradeIds().size());
		assertTrue(positionValueProp.getTradeIds().contains(3));

		// ACC-231|GOOG
		positionValueProp = positionCache
				.get(new PositionKey("GOOG", "ACC-231"));
		assertEquals(0, positionValueProp.getQuantity());
		assertEquals(1, positionValueProp.getTradeIds().size());
		assertTrue(positionValueProp.getTradeIds().contains(4));

		// verify trade cache is ok
		Map<Integer, Trade> tradeCache = Cache.getTradeCache();
		assertEquals(950, tradeCache.get(1).getQuantity());
		assertEquals(450, tradeCache.get(2).getQuantity());
		assertEquals(95, tradeCache.get(3).getQuantity());
		assertEquals(0, tradeCache.get(4).getQuantity());

		// nothing in cancel queue
		assertEquals(0, Cache.getPendingCancels().size());
	}

	@Test
	public void eventOrderAndThreadSafetyTest() throws InterruptedException,
			ExecutionException {
		// step -1
		// create many securities - SEC1, SEC2, SEC3 and so on
		// create many accounts - ACC1, ACC2, ACC3 and so on

		// step -2
		// create a new trade with quantity 100 for every security-account
		// combination.
		// no of new trades = (no of accounts) * (no of securities)
		// if security is odd side is buy else sell

		// step -3
		// for every new trade create 10 amend trades
		// amend the quantity to a random number between 1 to 1000

		// step -4
		// for every new trade create an amend trade with quantity 200

		// step -5
		// put all trades in a single list
		// shuffle the list

		// step -6
		// load the list using 8 threads

		// step -7
		// ensure quantity of every odd security is 200 and even security is
		// -200

		final int NUM_SECURITIES = 100;
		final int NUM_ACCOUNTS = 100;
		final int NUM_THREADS = 8;
		final int NUM_AMENDS = 10;

		// step -1
		List<String> securities = new ArrayList<String>();
		for (int i = 0; i < NUM_SECURITIES; i++) {
			securities.add("SEC" + i);
		}

		List<String> accounts = new ArrayList<String>();
		for (int i = 0; i < NUM_ACCOUNTS; i++) {
			accounts.add("ACC" + i);
		}

		assertEquals(NUM_SECURITIES, securities.size());
		assertEquals(NUM_ACCOUNTS, accounts.size());

		// step -2 create new trades with quantity 100, side buy if security is
		// odd else
		// sell
		List<Trade> newTrades = new ArrayList<>();
		int tradeId = 0;
		for (int i = 0; i < securities.size(); i++) {
			int quantity = 100;
			boolean buy = true;
			if (i % 2 == 0)
				buy = false;

			String security = securities.get(i);
			assertTrue(security != null);
			for (int j = 0; j < accounts.size(); j++) {
				String account = accounts.get(j);

				tradeId++;
				Trade trade = new Trade(tradeId, 1, security, quantity, buy,
						account, Operation.NEW);
				newTrades.add(trade);
			}
		}

		assertEquals(NUM_ACCOUNTS * NUM_SECURITIES, tradeId);
		assertEquals(NUM_ACCOUNTS * NUM_SECURITIES, newTrades.size());

		// step -3: create 10 amend trade for each new trade with random
		// quantity and random side
		List<Trade> amends = new ArrayList<>();
		Random random = new Random();
		for (Trade trade : newTrades) {
			for (int i = 0; i < NUM_AMENDS; i++) {
				int quantity = random.nextInt(1000) + 1; // random no >=1 and <=
															// 1000
				boolean buy = random.nextBoolean();
				Trade amend = new Trade(trade.getTradeId(),
						trade.getTradeVersion() + i + 1, trade.getSecurity(),
						quantity, buy, trade.getAccountNo(),
						trade.getOperation());
				amends.add(amend);
			}
		}
		assertEquals(newTrades.size() * 10, amends.size());

		// step -4: for every new trade create an amend trade with quantity 200
		for (Trade trade : newTrades) {
			Trade amend = new Trade(trade.getTradeId(), trade.getTradeVersion()
					+ NUM_AMENDS + 1, trade.getSecurity(), 200, trade.isBuy(),
					trade.getAccountNo(), trade.getOperation());
			amends.add(amend);
		}

		assertEquals(newTrades.size() * 11, amends.size());

		// step -5: put everything in a list and shuffle it
		List<Trade> allTrades = new ArrayList<>();
		allTrades.addAll(newTrades);
		allTrades.addAll(amends);
		assertEquals(newTrades.size() + amends.size(), allTrades.size());
		Collections.shuffle(allTrades);

		ExecutorService executorService = Executors
				.newFixedThreadPool(NUM_THREADS);

		List<Future<?>> futures = new ArrayList<>(allTrades.size());
		for (int i = 0; i < allTrades.size(); i++) {
			futures.add(null);
		}
		assertEquals(allTrades.size(), futures.size());

		for (int i = 0; i < allTrades.size(); i++) {
			final Trade trade = allTrades.get(i);
			Future<?> future = executorService.submit(new Runnable() {

				@Override
				public void run() {
					Cache.update(trade);
				}
			});
			futures.set(i, future);
		}

		// ensure no exception. future.get() will throw exception if there was
		// any exception in the thread

		for (Future<?> future : futures) {
			future.get();
		}

		Map<PositionKey, PositionValue> positionCache = Cache
				.getPositionCache();
		assertEquals(NUM_ACCOUNTS * NUM_SECURITIES, positionCache.size());

		// step -7
		// ensure quantity of every odd security is 200 and even security is
		// -200

		tradeId = 0;
		for (int i = 0; i < securities.size(); i++) {
			String security = securities.get(i);

			int quantity = 200;
			if (i % 2 == 0)
				quantity = -200;
			for (int j = 0; j < accounts.size(); j++) {
				String account = accounts.get(j);
				tradeId++;

				PositionKey key = new PositionKey(security, account);
				assertTrue(positionCache.containsKey(key));

				PositionValue value = positionCache.get(key);
				assertEquals(quantity, value.getQuantity());
				assertTrue(value.getTradeIds().contains(tradeId));
			}
		}

		System.out
				.println("Load testing to verify thread safety and event order insensitivity done with: "
						+ allTrades.size() + " trades");

		executorService.shutdown();
		executorService.awaitTermination(60, TimeUnit.SECONDS);

	}

	@Test
	public void pendingCancel() {
		Trade t1v1 = new Trade(1, 1, "MSFT", 100, true, "ACC-123",
				Operation.NEW);
		Trade t1v2 = new Trade(1, 2, "MSFT", 0, true, "ACC-123",
				Operation.CANCEL);
		Trade t1v3 = new Trade(1, 3, "MSFT", 0, true, "ACC-123",
				Operation.CANCEL); // duplicate cancel

		// cancel event before original trade
		Cache.update(t1v2);
		Cache.update(t1v2);
		Cache.update(t1v3);

		Map<PositionKey, PositionValue> positionCache = Cache
				.getPositionCache();
		assertEquals(0, positionCache.size());
		Map<Integer, Trade> pendingCancels = Cache.getPendingCancels();
		assertEquals(1, pendingCancels.size());

		Cache.update(t1v1);
		assertEquals(1, positionCache.size());
		PositionValue value = positionCache.get(new PositionKey(t1v1
				.getSecurity(), t1v1.getAccountNo()));
		assertEquals(0, value.getQuantity());
		assertEquals(1, value.getTradeIds().size());
		assertTrue(value.getTradeIds().contains(1));

		// pending cancel queue should be empty
		assertEquals(0, pendingCancels.size());
	}

	@Test
	public void differentDetailsInLaterVersion() {
		Trade v1 = new Trade(1, 1, "MSFT", 100, true, "ACC-123", Operation.NEW);
		Trade v2 = new Trade(1, 2, "GOOG", 40, false, "ACC-456",
				Operation.AMEND);

		Cache.update(v1);
		Cache.update(v2);

		Map<PositionKey, PositionValue> positionCache = Cache
				.getPositionCache();
		PositionValue positionValueProp = positionCache.get(new PositionKey(
				"MSFT", "ACC-123"));
		assertEquals(0, positionValueProp.getQuantity());
		assertEquals(0, positionValueProp.getTradeIds().size());

		positionValueProp = positionCache
				.get(new PositionKey("GOOG", "ACC-456"));
		assertEquals(-40, positionValueProp.getQuantity());
		assertEquals(1, positionValueProp.getTradeIds().size());
		assertTrue(positionValueProp.getTradeIds().contains(1));
	}
}
